package com.vote.csdn.service;


import cn.hutool.http.HttpUtil;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import com.vote.csdn.controller.pojo.*;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author: larry.xiang
 * @description: 业务类，相关业务都写这里，项目比较小，业
 * 务比较单一所以不分多个业务类
 */
@Service
public class CsdnService {


    public List<Csdn> csdnList = new ArrayList<Csdn>();

    public int sum = 0;

    // 中奖人姓名
    public String userName = "等待抽奖中";


    /*
     * WeBASE-Front api地址
     */
    final String WEBASE_FRONT_URL="http://192.168.119.133:5002";



    /**
     * 执行合约
     *
     * @param param 合约参数
     * @return
     */
    public String handle(String param) {
        String url =WEBASE_FRONT_URL+"/WeBASE-Front/trans/handle";
        String body = "{\n" +
                "    \"user\":\"0xf0d04e0cc9b16528207027f1d5020e402096b44e\",\n" +
                "    \"contractName\":\"APISampleOracle\",\n" +
                "    \"contractAddress\":\"0x5ffbf18cfbe8c5b8fee09ccde4f5165007a6043e\",\n" +
                "    \"funcName\":\"" + param + "\",\n" +
                "    \"contractAbi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracleAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"Fulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"Requested\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"EXPIRY_TIME\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_requestId\",\"type\":\"bytes32\"},{\"internalType\":\"int256\",\"name\":\"_result\",\"type\":\"int256\"}],\"name\":\"__callback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"checkIdFulfilled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getById\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUrl\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"request\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"result\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_url\",\"type\":\"string\"}],\"name\":\"setUrl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}] ,\n" +
                "    \"groupId\" :\"1\",\n" +
                "    \"useCns\": false\n" +
                "}";
        String res = HttpUtil.post(url, body);
        if (param.equals("get")) {
            // 处理格式
            res = res.replace("[", "").replace("]", "").replace("000000000000000000", "");
        }
        return res;
    }


    /**
     * 通过用户id获取用户名（csdn）
     * @param id 用户的排名id
     * @return
     */
    public String getUserNameById(int id) {
        String[] name = {null};
        csdnList.stream().filter(csdn -> csdn.getNumber() == id).forEach(csdn -> {
            name[0] = csdn.getName();
        });
        return name[0];
    }


    /**
     * 获取排名，看看是否进top100
     *
     * http://csdn.itrhx.com/是个人搭建的排名页面，可能会失效，如果失效则判断进入了TOP100
     *
     * @return
     */
    public boolean getRanking() {
        try {
            String html = HttpUtil.get("http://csdn.itrhx.com/");
            Document doc = Jsoup.parse(html);
            Elements els = doc.getElementsByTag("tr");
            for (int i=0;i<els.size();i++
            ) {
                if (els.get(i).html().contains("ws327443752")&&i<=100) {
                    return true;
                }
            }
        }catch (Exception ex){

            return  true;

        }

        return false;
    }
    /**
     * 抽奖方法
     * @param orignalRates 商品中奖概率列表，保证顺序和实际物品对应
     * @return 中奖商品索引
     */
    public  int lottery(List<Double> orignalRates) {

        if (orignalRates == null || orignalRates.isEmpty()) {
            return -1;
        }

        int size = orignalRates.size();

        // 计算总概率，这样可以保证不一定总概率是1
        double sumRate = 0d;
        for (double rate : orignalRates) {
            sumRate += rate;
        }

        // 计算每个物品在总概率的基础下的概率情况
        List<Double> sortOrignalRates = new ArrayList<>(size);
        Double tempSumRate = 0d;
        for (double rate : orignalRates) {
            tempSumRate += rate;
            sortOrignalRates.add(tempSumRate / sumRate);
        }

        // 根据区块值来获取抽取到的物品索引
        double nextDouble = Math.random();
        sortOrignalRates.add(nextDouble);
        Collections.sort(sortOrignalRates);

        return sortOrignalRates.indexOf(nextDouble);
    }


    /**
     * 触发抽奖逻辑
     * @return
     */
    public String handleLottery() {
        List<NameDTO> nameDTOS = new ArrayList<>();

        for (int i = 0; i < csdnList.size(); i++) {
            double f1 = new BigDecimal((float)csdnList.get(i).getVote()/sum).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
            nameDTOS.add(new NameDTO(i + 1, csdnList.get(i).getName(), csdnList.get(i).getNumber() + "", f1));
        }

        // 存储概率
        List<Double> orignalRates = new ArrayList<>(nameDTOS.size());
        for (NameDTO gift : nameDTOS) {
            double probability = gift.getProbability();
            if (probability < 0) {
                probability = 0;
            }
            orignalRates.add(probability);
        }

        // 统计
        Map<Integer, Integer> count = new HashMap<>();

        // 次数
        double num = 1;
        for (int i = 0; i < num; i++) {
            int orignalIndex = lottery(orignalRates);
            Integer value = count.get(orignalIndex);
            count.put(orignalIndex, value == null ? 1 : value + 1);
        }

        String id=null;
        for (Map.Entry<Integer, Integer> entry : count.entrySet()) {
            id=nameDTOS.get(entry.getKey()).getNo();
        }
        return id;
    }


    /**
     * 获取csdn投票相关数据
     */
    public void getCsdnContent() {
        csdnList=new ArrayList<Csdn>();
        sum=0;
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("username" , "ws327443752");
        params.put("page" , "1");
        params.put("pageSize" , "200");
        String json = HttpUtil.post("https://bss.csdn.net/m/topic/blog_star2020/getRanking", params);
        JSONObject jsonObject= JSONUtil.parseObj(json);
        JSONArray ja=  jsonObject.getJSONArray("data");

        for (int i = 0; i < ja.size(); i++) {
            Csdn csdn=new Csdn();
            JSON jsonStr = (JSON) ja.get(i);
            String uName = jsonStr.getByPath("nick_name").toString();
            csdn.setName(uName);
            String voteNum = jsonStr.getByPath("voteNum").toString();
            csdn.setVote(Integer.parseInt(voteNum));
            sum+=csdn.getVote();
            String level = jsonStr.getByPath("level").toString();
            csdn.setLevel(Integer.parseInt(level));
            String codeLevel = jsonStr.getByPath("codeLevel").toString();
            csdn.setCodeLevel(Integer.parseInt(codeLevel));
            int number = Integer.parseInt(jsonStr.getByPath("number").toString());
            csdn.setNumber(number);
            csdnList.add(csdn);
        }
    }
}
